package com.lucifer.d.security.data.accept;

import com.lucifer.d.security.data.annotation.DataCompletion;
import com.lucifer.d.security.data.config.DataCompletionConfig;
import com.lucifer.d.security.data.enums.DataCompletionEnum;
import com.lucifer.d.security.data.enums.DataTransferEnum;
import com.lucifer.d.security.data.enums.DataTypeEnum;
import com.lucifer.d.security.data.model.DataCompletionModel;
import com.lucifer.d.security.transfer.SignTransfer;
import com.lucifer.d.security.transfer.UserTransfer;
import com.lucifer.d.security.util.BasicDataTypeVerify;
import com.lucifer.d.util.SpringUtil;
import com.lucifer.d.util.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 参数信息自动补全过滤
 *
 * @author Lucifer
 */
@Aspect
public class DataCompletionAspect {

    @Autowired
    private UserTransfer userTransfer;

    @Autowired
    private SignTransfer signTransfer;

    @Autowired
    private DataCompletionConfig config;

    /**
     * 定义切入点，为@DataCompletion注解
     */
    @Pointcut("@annotation(com.lucifer.d.security.data.annotation.DataCompletion)")
    public void dataCompletionAspect() {
    }

    /**
     * 切入点环形执行内容
     *
     * @param point 切点对象映射
     * @return
     * @throws Throwable
     */
    @Around("dataCompletionAspect()")
    public Object doBefore(ProceedingJoinPoint point) throws Throwable {
        // 获取对应方法注解值
        MethodSignature signature = (MethodSignature)point.getSignature();
        DataCompletion dataCompletion = signature.getMethod().getAnnotation(DataCompletion.class);
        String useType = dataCompletion.type();
        String methodType = dataCompletion.value();
        // 获取切入点对应参数
        Object[] args = point.getArgs();
        //FIXME 获取方法参数（全参数补全）
        for (int i = 0; i<args.length; i++){
            Object goalObj = args[i];
            // 排除基本类型封装类
            if (BasicDataTypeVerify.basicDataTypeVerify(goalObj)){
                List<Object> goals = new ArrayList<>();
                Boolean isList = false;
                List<Object> end = new ArrayList<>();
                if (goalObj instanceof List){
                    goals = (List<Object>) goalObj;
                    isList = true;
                }else {
                    goals.add(goalObj);
                }
                for (Object goal : goals){
                    // 参数类
                    Class<?> clazz = goal.getClass();
                    // 获取类对应变量参数（全反射）
                    Field[] fields = clazz.getDeclaredFields();
                    for (Field field : fields){
                        // 拼装方法名
                        String fieldName = field.getName();
                        String first = fieldName.substring(0, 1).toUpperCase();
                        String after = fieldName.substring(1);
                        // 拼接set方法名
                        String methodSet = "set" + first + after;
                        // 拼接get方法名
                        String methodGet = "get" + first + after;
                        for (DataCompletionModel model : config.model()){
                            // 是否存在填充
                            if (field.getAnnotation(model.getAnno()) != null){
                                // 判断是否存在填充参数
                                Object invoke = clazz.getDeclaredMethod(methodGet).invoke(goal);
                                // 如不存在，则执行填充业务
                                if (invoke == null || StringUtil.isEmpty(String.valueOf(invoke))){
                                    // 判断填充前提
                                    if (methodType.equals(model.getPremise())){
                                        // 初始化执行对象
                                        Object bean = null;
                                        // 属性填充不存在执行对象
                                        if (!model.getType().equals(DataCompletionEnum.MODEL.type)){
                                            try {
                                                bean = SpringUtil.getBean(model.getMethodClass());
                                                if (bean == null){
                                                    bean = model.getMethodClass().newInstance();
                                                }
                                            }catch (Exception e){
                                                bean = model.getIsStatic() ? model.getMethodClass() : model.getMethodClass().newInstance();
                                            }
                                        }
                                        // 值对象
                                        Object value = null;
                                        // 独立填充业务执行
                                        if (model.getType().equals(DataCompletionEnum.OWN.type)){
                                            // 取值
                                            // 静态方法
                                            if (model.getIsStatic()){
                                                value = ((Class) bean).getDeclaredMethod(model.getMethodName(), model.getMethodColumn()).invoke(null, model.getMethodValue());
                                            }
                                            // 对象方法
                                            else {
                                                // 移除IOC容器代理对象类，取原始类
                                                String className = bean.getClass().getName();
                                                int endPrefix = className.indexOf("$");
                                                className = endPrefix <= 0 ? className : className.substring(0 , endPrefix);
                                                value = Class.forName(className).getDeclaredMethod(model.getMethodName(), model.getMethodColumn()).invoke(bean, model.getMethodValue());
                                            }
                                        }
                                        // 方法填充业务执行
                                        else if (model.getType().equals(DataCompletionEnum.METHOD.type)) {
                                            Object user = getUser(model.getTransferType(), useType);
                                            // 如果不存在用户信息，跳过填充
                                            if (user == null){
                                                continue;
                                            }
                                            // 方法参数集合
                                            List<Object> columnValues = new ArrayList<>();
                                            // 参数获取
                                            for (String property : model.getMethodProperty()){
                                                // 拼装get方法
                                                String userGet = "get" + property.substring(0, 1).toUpperCase() + property.substring(1);
                                                columnValues.add(user.getClass().getDeclaredMethod(userGet).invoke(user));
                                            }
                                            // 取值
                                            // 静态方法
                                            if (model.getIsStatic()){
                                                value = ((Class) bean).getDeclaredMethod(model.getMethodName(), model.getMethodColumn()).invoke(null, columnValues.toArray());
                                            }
                                            // 对象方法
                                            else {
                                                // 移除IOC容器代理对象类，取原始类
                                                String className = bean.getClass().getName();
                                                int endPrefix = className.indexOf("$");
                                                className = endPrefix <= 0 ? className : className.substring(0 , endPrefix);
                                                value = Class.forName(className).getDeclaredMethod(model.getMethodName(), model.getMethodColumn()).invoke(bean, columnValues.toArray());
                                            }
                                        }
                                        // 属性填充业务执行
                                        else if (model.getType().equals(DataCompletionEnum.MODEL.type)) {
                                            Object user = getUser(model.getTransferType(), useType);
                                            // 如果不存在用户信息，跳过填充
                                            if (user == null){
                                                continue;
                                            }
                                            // 拼装get方法
                                            String userGet = "get" + model.getColumn().substring(0, 1).toUpperCase() + model.getColumn().substring(1);
                                            // 取值
                                            value = user.getClass().getDeclaredMethod(userGet).invoke(user);
                                        }
                                        // 值类型判断
                                        if (model.getValueType().equals(DataTypeEnum.STRING.type)){
                                            // 执行填充
                                            clazz.getDeclaredMethod(methodSet, String.class).invoke(goal,value == null ? value : String.valueOf(value));
                                        } else if (model.getValueType().equals(DataTypeEnum.INTEGER.type)){
                                            // 执行填充
                                            clazz.getDeclaredMethod(methodSet, Integer.class).invoke(goal,value == null ? value : Integer.valueOf(String.valueOf(value)));
                                        } else if (model.getValueType().equals(DataTypeEnum.DOUBLE.type)) {
                                            // 执行填充
                                            clazz.getDeclaredMethod(methodSet, Double.class).invoke(goal,value == null ? value : Double.valueOf(String.valueOf(value)));
                                        } else if (model.getValueType().equals(DataTypeEnum.LONG.type)) {
                                            // 执行填充
                                            clazz.getDeclaredMethod(methodSet, Long.class).invoke(goal,value == null ? value : Long.valueOf(String.valueOf(value)));
                                        }else {
                                            // 执行填充
                                            clazz.getDeclaredMethod(methodSet, Long.class).invoke(goal,value);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    end.add(goal);
                }
                // 清空栈内存占用
                goals.clear();
                if (isList){
                    args[i] = end;
                }else {
                    args[i] = end.get(0);
                }
            }
        }
        // 执行业务
        Object proceed = point.proceed(args);
        return proceed;
    }

    private Object getUser(String transferType, String useType){
        // security黑盒子获取角色信息
        Object user = null;
        if ("isService".equals(useType)){
            if (DataTransferEnum.USER.type.equals(transferType)){
                user = userTransfer.getSecurityUser();
            }else {
                user = signTransfer.getSecurityUser();
            }
        }
        return user;
    }

}
